﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Data.Objects;
namespace Fcdbas.Infrastructure.UnitOfWork
{
    /// <summary>
    /// 实现工作单元的的功能
    /// </summary>
    public class UnitOfWork : IUnitOfWork
    {
        private Dictionary<System.Data.Objects.DataClasses.EntityObject, IUnitOfWorkRepository> addedEntities;
        private Dictionary<System.Data.Objects.DataClasses.EntityObject, IUnitOfWorkRepository> changedEntities;
        private Dictionary<System.Data.Objects.DataClasses.EntityObject, IUnitOfWorkRepository> removedEntities;
        
        private Dictionary<string, IUnitOfWorkRepository> commandEntities;
        private Dictionary<string, object[]> commandPEntities;
        private Dictionary<string, IUnitOfWorkRepository> functionEntities;
        private Dictionary<string, ObjectParameter[]> functionPEntities;
        private Dictionary<string, IUnitOfWorkRepository> nonQueryEntities;
        private Dictionary<string, Oracle.DataAccess.Client.OracleParameter[]> nonQueryPEntities;
        private string strLastError = "";
        //...
    
        public UnitOfWork()
        {
            addedEntities =
                new Dictionary<System.Data.Objects.DataClasses.EntityObject, IUnitOfWorkRepository>();
            changedEntities =
                new Dictionary<System.Data.Objects.DataClasses.EntityObject, IUnitOfWorkRepository>();
            removedEntities =
                new Dictionary<System.Data.Objects.DataClasses.EntityObject, IUnitOfWorkRepository>();
            commandEntities = new Dictionary<string, IUnitOfWorkRepository>();
            commandPEntities = new Dictionary<string, object[]>();
            functionEntities = new Dictionary<string, IUnitOfWorkRepository>();
            functionPEntities = new Dictionary<string, ObjectParameter[]>();

            nonQueryEntities = new Dictionary<string, IUnitOfWorkRepository>();
            nonQueryPEntities = new Dictionary<string, Oracle.DataAccess.Client.OracleParameter[]>();
        }

        public void RegisterAdded(System.Data.Objects.DataClasses.EntityObject entity, IUnitOfWorkRepository repository)
        {
            this.addedEntities.Add(entity, repository);
        }

        public void RegisterChangeded(System.Data.Objects.DataClasses.EntityObject entity, IUnitOfWorkRepository repository)
        {
            this.changedEntities.Add(entity, repository);
        }

        public void RegisterRemoved(System.Data.Objects.DataClasses.EntityObject entity, IUnitOfWorkRepository repository)
        {
            this.removedEntities.Add(entity, repository);
        }
        public string GetLastError()
        {
            return strLastError;
        }
        public bool Commit(ObjectContext objContext,bool IsLocal = false)
        {
            //var cnn = (System.Data.EntityClient.EntityConnection)objContext.Connection;

            //if (cnn.State == System.Data.ConnectionState.Closed)
            //{
            //    cnn.Open();
            //}
            bool bSave = true;
            try
            {
               // System.Data.EntityClient.EntityTransaction transaction = cnn.BeginTransaction();
                using (TransactionScope scope = new TransactionScope())
                {
                    foreach (var entity in this.removedEntities.Keys)
                    {
                        this.removedEntities[entity].PersistDeletedItem(entity, IsLocal);
                    }

                    foreach (var entity in this.addedEntities.Keys)
                    {
                        this.addedEntities[entity].PersistNewItem(entity, IsLocal);
                    }

                    foreach (var entity in this.changedEntities.Keys)
                    {
                        this.changedEntities[entity].PersistUpdatedItem(entity, IsLocal);
                    }
                    
                    foreach (var sql in this.commandEntities.Keys)
                    {
                        this.commandEntities[sql].PersistExcuteStoreCommand(sql, this.commandPEntities[sql]);
                    }
                    foreach (var sql in this.functionEntities.Keys)
                    {
                        this.functionEntities[sql].PersistExcuteFunction(sql, this.functionPEntities[sql]);
                    }
                    foreach (var sql in this.nonQueryEntities.Keys)
                    {
                        this.nonQueryEntities[sql].PersistExcuteNonQuery(sql, this.nonQueryPEntities[sql]);
                    }
                    // transaction.Commit();
                    objContext.SaveChanges(SaveOptions.None);
                    scope.Complete();
                }
            }
            catch (System.Data.OptimisticConcurrencyException)
            {
                objContext.Refresh(RefreshMode.ClientWins, this.addedEntities.Keys);
                objContext.Refresh(RefreshMode.ClientWins, this.changedEntities.Keys);
                objContext.Refresh(RefreshMode.ClientWins, this.removedEntities.Keys);
                objContext.SaveChanges(SaveOptions.None);
               // transaction.Commit();
            }
            catch (Exception ex)
            {
                strLastError = ex.Message;
                Fcdbas.Core.Log.XTrace.WriteException(ex);
                bSave = false;
            }
            finally
            {
                foreach (var entity in this.addedEntities.Keys)
                {
                    objContext.Detach(entity);
                    // objContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Unchanged);
                }
                if (!IsLocal)
                {
                    foreach (var entity in this.changedEntities.Keys)
                    {
                        objContext.Detach(entity);
                        // objContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Unchanged);
                    }
                }
                if (IsLocal)
                {
                    foreach (var entity in this.changedEntities.Keys)
                    {
                        //
                         objContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Unchanged);
                         objContext.Detach(entity);
                    }
                }
                if (!IsLocal)
                {
                    foreach (var entity in this.removedEntities.Keys)
                    {
                        objContext.Detach(entity);
                        //objContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Unchanged);
                    }
                }
                this.removedEntities.Clear();
                this.addedEntities.Clear();
                this.changedEntities.Clear();
                this.functionEntities.Clear();
                this.functionPEntities.Clear();
                this.commandEntities.Clear();
                this.commandPEntities.Clear();
                //cnn.Close();
            }
            return bSave;
          //  }
        }


        public void RegisterCommand(string sql, object[] parameters, IUnitOfWorkRepository repository)
        {
            this.commandEntities.Add(sql, repository);
            this.commandPEntities.Add(sql,parameters);
        }

        public void RegisterFunction(string sql, ObjectParameter[] parameters, IUnitOfWorkRepository repository)
        {
            this.functionEntities.Add(sql, repository);
            this.functionPEntities.Add(sql, parameters);
        }
        public void RegisterNonQuery(string sql, Oracle.DataAccess.Client.OracleParameter[] parameters, IUnitOfWorkRepository repository)
        {
            this.nonQueryEntities.Add(sql, repository);
            this.nonQueryPEntities.Add(sql, parameters);
        }
    }
}
